package NetFrameWork

import (
	"NetFrameWork/core/hub"
	"NetFrameWork/util/crypt"
	"NetFrameWork/util/packet"
	"bufio"
	"encoding/hex"
	"errors"
	"fmt"
	"log"
	"net"
	"time"
)

type ClientConnection struct {
	conn       net.Conn
	ver        uint16
	id         uint64
	lastTime   int64
	closed     bool
	server     hub.Server
	stopChan   chan bool
	writeChan  chan []byte
	scanner    *bufio.Scanner
	sendCrypto *CryptUtil.AESOFB
	recvCrypto *CryptUtil.AESOFB
}

func (this *ClientConnection) Server() hub.Server {
	return this.server
}

func (this *ClientConnection) GetId() uint64 {
	return this.id
}

func (this *ClientConnection) GetLastTime() int64 {
	return this.lastTime
}

func (this *ClientConnection) IP() string {
	return this.conn.RemoteAddr().String()
}

func NewClientConnection(server *Server, conn net.Conn, sendCrypto, recvCrypto *CryptUtil.AESOFB) *ClientConnection {
	scanner := bufio.NewScanner(conn)

	client := ClientConnection{
		conn:       conn,
		scanner:    scanner,
		closed:     false,
		sendCrypto: sendCrypto,
		recvCrypto: recvCrypto,
		id:         server.getNextId(),
		server:     server,
		ver:        001,
		lastTime:   time.Now().Unix(),
		stopChan:   make(chan bool),
		writeChan:  make(chan []byte, 10),
	}
	client.scanner.Split(func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		available := len(data)
		// 已经扫描到结尾了
		if available >= 4 {
			header := data[:4]
			if client.recvCrypto.CheckPacket(header) {
				packetLength := CryptUtil.GetPacketLength(header)
				if available >= 4+packetLength {
					token = data[4 : 4+packetLength]
					client.recvCrypto.Crypt(token)
					return 4 + packetLength, token, nil
				}
			} else {
				return 0, nil, errors.New("invalid packet header")
			}
		}

		if atEOF {
			err = errors.New("Connection is close")
			token = data
			return
		} else {
			return 0, nil, nil
		}
		// 表示现在不能分割，向Reader请求更多的数据
	})
	go client.write()
	return &client
}

func (this *ClientConnection) Close() {
	if !this.closed {
		if this.server.(*Server).CloseCallBack != nil {
			this.server.(*Server).CloseCallBack(this)
		}
		this.closed = true
		close(this.stopChan)
		this.server.(*Server).hub.DelCon(this.id)
		this.conn.Close()
	}
}

func (this *ClientConnection) read() {
	defer this.Close()
	for {
		select {
		case <-this.stopChan:
			return
		default:
			if this.scanner.Err() != nil {
				log.Println(this.scanner.Err())
				return
			}

			if this.scanner.Scan() {
				this.lastTime = time.Now().Unix()
				bytes := this.scanner.Bytes()
				reader := packet.NewPacketReader(bytes)
				err := this.server.(*Server).handler.Handle(this, reader)
				if err != nil {
					log.Println(err)
				}
			}
		}
	}

}

func (this *ClientConnection) write() {
	defer this.Close()
	for {
		select {
		case <-this.stopChan:
			return
		case packet := <-this.writeChan:

			header := this.sendCrypto.GetPacketHeader(uint16(len(packet)))
			this.sendCrypto.AesCrypt(packet)
			var newPacket []byte
			newPacket = append(newPacket, header...)
			newPacket = append(newPacket, packet...)

			_, err := this.conn.Write(newPacket)
			if err != nil {
				log.Println(err)
				return
			}
		}
	}
}

func (this *ClientConnection) WriteData(data []byte) {
	var bb []byte
	bb = append(bb, data...)
	fmt.Println(hex.Dump(bb))
	this.writeChan <- bb
}
